"use client"; import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState } from "react"; import { hasQuestionAnswerValue, QuestionAnswersProvider, useQuestionAnswers, } from "@/components/questions/question-answer-storage"; import QuestionButton from "@/components/questions/question-button"; import { QuestionCheckbox } from "@/components/questions/question-checkbox"; import QuestionDate from "@/components/questions/question-date"; import QuestionDropdown from "@/components/questions/question-dropdown"; import QuestionExitNavigationButton from "@/components/questions/question-exit-navigation-button"; import QuestionFile from "@/components/questions/question-file"; import QuestionNumber from "@/components/questions/question-number"; import QuestionPhone from "@/components/questions/question-phone"; import QuestionPhoto from "@/components/questions/question-photo"; import QuestionRadio from "@/components/questions/question-radio"; import QuestionSectionFlow from "@/components/questions/question-section-flow"; import QuestionSlider from "@/components/questions/question-slider"; import QuestionText from "@/components/questions/question-text"; import NavigationButton from "@/components/ui/navigation-button"; import StickyHeader from "@/components/ui/sticky-header"; import { PageBackground } from "@/components/utils/page-background"; import { getQuestionListItemBySlug, isQuestionListItemVisibleForProfile, isQuestionRequiredForProfile, isQuestionVisibleForProfile, type QuestionField, } from "@/data/question-data"; import type { MarriageGender } from "@/hooks/marriage/types"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; import { defaultLocale, type Locale } from "@/i18n/config"; import { useI18n } from "@/i18n/provider"; import TestIntroPage from "@/components/questions/test-intro-page"; import TestQuestionsFlow, { type TestQuestion } from "@/components/questions/test-questions-flow"; import AnswerPaceSheet from "./answer-pace-sheet"; type QuestionDetailClientProps = { closeLabel: string; continueLabel: string; description: string; informationLabel: string; itemSlug: string; locale?: Locale; questionsListHref: string; title: string; }; type StoredQuestionField = { label?: string; value?: unknown; }; type StoredAnswers = { fields?: StoredQuestionField[]; }; function getQuestionStorageKey(slug: string) { return `marriage:sections:${slug}:answers`; } function parseStoredAge(value: unknown) { if (typeof value === "number" && Number.isFinite(value)) { return value; } if (typeof value === "string") { const trimmedValue = value.trim(); if (!trimmedValue) { return null; } const numericAge = Number(trimmedValue); if (Number.isFinite(numericAge)) { return numericAge; } const dateOfBirth = new Date(trimmedValue); if (Number.isNaN(dateOfBirth.getTime())) { return null; } const today = new Date(); let age = today.getFullYear() - dateOfBirth.getFullYear(); const hasBirthdayPassed = today.getMonth() > dateOfBirth.getMonth() || (today.getMonth() === dateOfBirth.getMonth() && today.getDate() >= dateOfBirth.getDate()); if (!hasBirthdayPassed) { age -= 1; } return age >= 0 ? age : null; } return null; } function getStoredAge() { try { const rawValue = window.localStorage.getItem( getQuestionStorageKey("personal_info"), ); if (!rawValue) { return null; } const storedAnswers = JSON.parse(rawValue) as StoredAnswers; const ageField = storedAnswers.fields?.find( (field) => field.label === "Age", ); if (ageField) { return parseStoredAge(ageField.value); } const dateOfBirthField = storedAnswers.fields?.find( (field) => field.label === "Date of Birth", ); return parseStoredAge(dateOfBirthField?.value); } catch { return null; } } function renderQuestion( question: QuestionField, questionIndex: number, disabled?: boolean, dobQuestion?: QuestionField, dobQuestionIndex?: number, ) { const compactTextHeight = question.type === "text" && (question.title.toLowerCase().includes("name") || question.title.toLowerCase().includes("email") || question.title.toLowerCase().includes("city") || question.title.toLowerCase().includes("residence") || question.title.toLowerCase().includes("location") || question.title.toLowerCase().includes("description") || question.title.toLowerCase().includes("short") || question.title.toLowerCase().includes("duration") || question.title.toLowerCase().includes("reason") || question.title.toLowerCase().includes("lifestyle") || question.title.toLowerCase().includes("marja") || question.title.toLowerCase().includes("range") || question.title.toLowerCase().includes("ethnicity") || question.title.toLowerCase().includes("nationality") || question.title.toLowerCase().includes("مدت") || question.title.toLowerCase().includes("علت") || question.title.toLowerCase().includes("بازه") || question.title.toLowerCase().includes("قومیت") || question.title.toLowerCase().includes("ملیت") || question.title.toLowerCase().includes("کوتاه") || question.title.toLowerCase().includes("سبک زندگی") || question.title.toLowerCase().includes("مرجع")) && !question.title.toLowerCase().includes("detailed") && !question.title.toLowerCase().includes("biography") ? "h-[54px] min-h-0 py-2" : undefined; switch (question.type) { case "button": return ( ); case "checkbox": return ( ); case "date": return ( ); case "dropdown": return ( ); case "file": return ( ); case "number": if ( question.title === "Age" && dobQuestion && dobQuestionIndex !== undefined ) { return ( ); } return ( ); case "phone": return ( ); case "photo": return ( ); case "radio": return ( ); case "slider": return ( ); case "text": return ( ); default: return null; } } function QuestionFlowWrapper({ visibleQuestions, itemSlug, dobQuestion, dobQuestionIndex, requiredQuestionsCount, continueLabel, questionsListHref, }: { visibleQuestions: QuestionField[]; itemSlug: string; dobQuestion?: QuestionField; dobQuestionIndex?: number; requiredQuestionsCount: number; continueLabel: string; questionsListHref: string; }) { const { getAnswerValue } = useQuestionAnswers(); return ( question.required ? [] : [index], )} > {visibleQuestions.map((question, questionIndex) => { let isDisabled = false; if (question.logic?.dependsOn) { const { title, values } = question.logic.dependsOn; const dependentQuestionIndex = visibleQuestions.findIndex( (q) => q.title === title, ); if (dependentQuestionIndex !== -1) { const answer = getAnswerValue( visibleQuestions[dependentQuestionIndex], dependentQuestionIndex, ); isDisabled = !values.includes(String(answer)); } } const answer = getAnswerValue(question, questionIndex); const hasAnswer = hasQuestionAnswerValue(answer ?? null); let isAnswered = hasAnswer; if (hasAnswer) { const isEmailQuestion = question.title.toLowerCase().includes("email") || question.title.includes("ایمیل"); if (isEmailQuestion) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; isAnswered = emailRegex.test(String(answer).trim()); } } return (
{renderQuestion( question, questionIndex, isDisabled, dobQuestion, dobQuestionIndex, )}
); })}
); } export default function QuestionDetailClient({ closeLabel, continueLabel, description, informationLabel, itemSlug, locale = defaultLocale, questionsListHref, title, }: QuestionDetailClientProps) { const router = useRouter(); const { dictionary: t } = useI18n(); const [isTestStarted, setIsTestStarted] = useState(false); const { data: profile, isLoading: isProfileLoading } = useMarriageProfileQuery(); const profileGender = profile?.gender; const age = getStoredAge(); const item = getQuestionListItemBySlug(itemSlug, locale); const profileContext = useMemo( () => ({ age, gender: profileGender as MarriageGender | null | undefined, }), [age, profileGender], ); const visibleQuestions = useMemo(() => { if (!item) { return []; } const hasDobQuestion = item.questions.some( (q) => q.title === "Date of Birth" || q.title === "تاریخ تولد", ); return item.questions .filter((question) => { if ( hasDobQuestion && (question.title === "Age" || question.title === "سن") ) { return false; } return isQuestionVisibleForProfile(question, profileContext); }) .map((question) => ({ ...question, required: isQuestionRequiredForProfile(question, profileContext), })); }, [item, profileContext]); const requiredQuestionsCount = useMemo( () => visibleQuestions.filter((q) => q.required).length, [visibleQuestions], ); useEffect(() => { if (isProfileLoading) { return; } if (!item || isQuestionListItemVisibleForProfile(item, profileContext)) { return; } router.replace(questionsListHref); }, [isProfileLoading, item, profileContext, questionsListHref, router]); if (isProfileLoading && item) { // Show component skeleton/layout structure while loading profile } else if (!item || !isQuestionListItemVisibleForProfile(item, profileContext)) { return null; } if (item && item.questions.length === 0) { if (isTestStarted) { const testQuestions: TestQuestion[] = item.slug === "glasser_5_needs_test" ? [ { id: 1, text: "How important is financial security and long-term stability in your life?", options: [ { label: "Very Low", value: 1 }, { label: "Low", value: 2 }, { label: "Moderate", value: 3 }, { label: "High", value: 4 }, { label: "Very High", value: 5 }, ], }, { id: 2, text: "To what extent do you value personal freedom and flexibility in daily choices?", options: [ { label: "Very Low", value: 1 }, { label: "Low", value: 2 }, { label: "Moderate", value: 3 }, { label: "High", value: 4 }, { label: "Very High", value: 5 }, ], }, { id: 3, text: "How much do you seek recognition and personal achievement in your career/life?", options: [ { label: "Very Low", value: 1 }, { label: "Low", value: 2 }, { label: "Moderate", value: 3 }, { label: "High", value: 4 }, { label: "Very High", value: 5 }, ], }, { id: 4, text: "How essential is fun, humor, and playfulness in your relationship?", options: [ { label: "Very Low", value: 1 }, { label: "Low", value: 2 }, { label: "Moderate", value: 3 }, { label: "High", value: 4 }, { label: "Very High", value: 5 }, ], }, { id: 5, text: "How deep is your need for emotional connection and belonging with a partner?", options: [ { label: "Very Low", value: 1 }, { label: "Low", value: 2 }, { label: "Moderate", value: 3 }, { label: "High", value: 4 }, { label: "Very High", value: 5 }, ], }, ] : [ { id: 1, text: "How many hours do you typically spend on social media each day?", options: [ { label: "Between 11 and 15 Years", value: "11_15" }, { label: "Between 16 and 25 Years", value: "16_25" }, { label: "Between 26 and 40 Years", value: "26_40" }, { label: "Over 40 Years", value: "over_40" }, ], }, { id: 2, text: "I prefer spending my free time engaging in quiet, reflective activities.", options: [ { label: "Strongly Agree", value: "strongly_agree" }, { label: "Agree", value: "agree" }, { label: "Neutral / Uncertain", value: "neutral" }, { label: "Disagree", value: "disagree" }, ], }, { id: 3, text: "When making important life decisions, I rely more on logical analysis than feelings.", options: [ { label: "Always Logical", value: "always_logical" }, { label: "Mostly Logical", value: "mostly_logical" }, { label: "Balanced", value: "balanced" }, { label: "Mostly Intuitive", value: "mostly_intuitive" }, ], }, { id: 4, text: "How do you handle unexpected changes to your planned routine?", options: [ { label: "Adapt quickly and calmly", value: "adapt_quick" }, { label: "Need a moment to adjust", value: "need_moment" }, { label: "Feel stressed but manage", value: "stressed" }, { label: "Prefer strict adherence to plans", value: "strict_plans" }, ], }, { id: 5, text: "In social gatherings, I usually initiate conversations with new acquaintances.", options: [ { label: "Very True", value: "very_true" }, { label: "Somewhat True", value: "somewhat_true" }, { label: "Rarely True", value: "rarely_true" }, { label: "Not True At All", value: "not_true" }, ], }, ]; return ( setIsTestStarted(false)} /> ); } const bulletKey = item.slug === "glasser_5_needs_test" ? "glasser" : "personality"; const bullets = t.questions.testIntroBullets[bulletKey]; return ( <>

{item.title}

{ setIsTestStarted(true); }} />
); } const dobQuestion = visibleQuestions.find( (question) => question.title === "Date of Birth", ); const dobQuestionIndex = visibleQuestions.findIndex( (question) => question.title === "Date of Birth", ); return ( <>

{item.title}

); }